/**
 * 
 */
package ua.kpi.fpm.km61.strat.sp.la;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Stratiyevskyy
 *
 */
public class LexicalAnalisys {

    private File inpFile;
    private List<ResString> reslist = new ArrayList<ResString>();
    private static final String DELIM = "\\s+";
    public static final String DELIMRX = "[,]|[;]|[{]|[}]";
    public static final String CONSTRX = "true|false|null";
    public static final String OPERATIONSRX = "[*]+|[!]+|[/]+|[+]+|[-]+|[(]|[|]|" +
		"[)]|[&]+|(<=)|(>=)|[>]+|(!=)|(==)|[<]|[(++)]+" +
		"|(--)|=";
    public static final String RESERVEDRX = "int|double|class|if|" +
    		"then|else|final|new|void|return|for|while|public|private|main";
    public static final String litRXd = "(\\d+[.]\\d+)";
    public static final String litRXi = "\\d+";
    public static final String idRX = "[a-zA-Z_]+\\d*[a-zA-Z_]*";
    public static final String dotRX = "\\w[.]\\w";
    
    public LexicalAnalisys(File file){
    	this.inpFile = file;
    }
    
    public List<MarkedString> delLineComments(){
	try{
	    List<MarkedString> strlist = new ArrayList<MarkedString>();
            FileReader is = new FileReader(this.inpFile);
            BufferedReader br = new BufferedReader(is);
            String tmp = "";
            int i = 1;
            while ((tmp = br.readLine()) != null){
            	if(!(tmp.startsWith("//") || tmp.startsWith("/*"))){
            		if (tmp.indexOf("//") > 0) {
            			tmp = tmp.substring(0, tmp.indexOf("//") - 1);
            		}
        	    MarkedString fw = new MarkedString();
        	    fw.setStrnum(i);
        	    fw.setStr(tmp);
        	    strlist.add(fw);
            	}
        	i++;
            }
            br.close();
            is.close(); 
            return strlist;
        }catch (IOException e){
            e.printStackTrace();
            	return null;
        }
    }
    
    public List<MarkedString> delLineComments(List<MarkedString> lm){
	int k = 0;
           while (k < lm.size()){
        	MarkedString m = lm.get(k);
        	String tmp = m.getStr();
            	if(!(tmp.startsWith("//"))){
            		if (tmp.indexOf("//") > 0) {
            			tmp = tmp.substring(0, tmp.indexOf("//"));
            		}
        	    m.setStr(tmp);
        	    k++;
            	} else{
            	lm.remove(k); 
            	}
            }
            return lm;
    }
    
    public List<MarkedString> delBlockComments() {
	try {
	    List<MarkedString> strlist = new ArrayList<MarkedString>();
	    FileReader is = new FileReader(this.inpFile);
	    BufferedReader br = new BufferedReader(is);
	    String tmp = "";
	    int i = 1;
	    while ((tmp = br.readLine()) != null) {
		if (tmp.indexOf("/*") >= 0 && tmp.lastIndexOf("*/") > 0) {
		    tmp = tmp.substring(0, tmp.indexOf("/*"))
			    + tmp.substring(
				    tmp.lastIndexOf("*/") + "*/".length(),
				    tmp.length());

		}
		MarkedString fw = new MarkedString();
		fw.setStrnum(i);
		fw.setStr(tmp);
		strlist.add(fw);
		i++;
	    }
	    br.close();
	    is.close();
	    return strlist;
	} catch (IOException e) {
	    e.printStackTrace();
	    return null;
	}
    }
    
    public List<MarkedString> delBlockCommentsML(List<MarkedString> lm) {
	int k = 0;
	while (k < lm.size()) {
	    MarkedString m = lm.get(k);
	    String tmp = m.getStr();
	    if (tmp.indexOf("*/") >= 0) {
		return new ArrayList<MarkedString>();
	    } else{
		if (tmp.indexOf("/*") >= 0) {
		    tmp = tmp.substring(0, tmp.indexOf("/*"));
			m.setStr(tmp);
			int l = k + 1;
			while (l < lm.size()) {
			    MarkedString m1 = lm.get(l);
			    String tmp1 = m1.getStr();
				if (tmp1.indexOf("*/") >= 0) {
				    tmp1 = tmp1.substring(tmp1.lastIndexOf("*/")+"*/".length(), tmp1.length());
				    m1.setStr(tmp1);
				    l++;
				    break;
				} else {
				    lm.remove(l);
				}
			}
		    m.setStr(tmp);
		}
		k++;
	    }
	}
	return lm;
    }

   public Vector<String> toLst(){
	try{
		Vector<String> strlist = new Vector<String>();
            FileReader is = new FileReader(this.inpFile);
            BufferedReader br = new BufferedReader(is);
            String tmp = "";
            while ((tmp = br.readLine()) != null){
        	    strlist.add(tmp);
            }
            br.close();
            is.close();
            return strlist;
        }catch (IOException e){
            e.printStackTrace();
            	return null;
        }
    }
    
    public List<MarkedString> buildLecsem(List<MarkedString> inp){
	List<MarkedString> l = new ArrayList<MarkedString>(); 
	for(int i = 0; i < inp.size(); i++){
	    Scanner scan = new Scanner(inp.get(i).getStr());
	    scan.useDelimiter(DELIM);
	    System.out.println(inp.get(i).getStr());
	    while (scan.hasNext()){
	    	String st = scan.next();
	    	if (!st.equals("")){
	    		MarkedString fw = new MarkedString();
	    		fw.setStrnum(inp.get(i).getStrnum());
	    		fw.setStr(st);
	    		fw.setColnum(inp.get(i).getStr().indexOf(st)+1);
	    		l.add(fw); 
	    	}
	    } 
	}
	return l;
    }
    
    public List<MarkedString> splitByRegexp(List<MarkedString> ls, 
    		String regexp, String lex){
    	List<MarkedString> l = new ArrayList<MarkedString>();
        Pattern p3 = Pattern.compile(regexp);
        for(int i = 0; i < ls.size(); i++){
            String[] words = p3.split(ls.get(i).getStr());
            int fi = 0;
            for(String word : words){
            	MarkedString fw = new MarkedString();
            	fw.setStrnum(ls.get(i).getStrnum());
            	fw.setStr(word);
            	fi = ls.get(i).getStr().indexOf(word, fi);
            	fw.setColnum(fi + ls.get(i).getColnum());
            	l.add(fw); 
            }
            Matcher m2 = p3.matcher(ls.get(i).getStr());
            fi = 0;
            while (m2.find()){
                String op = m2.group();
                ResString fw = new ResString();
                fw.setStrnum(ls.get(i).getStrnum());
                fw.setStr(op);
                fi = ls.get(i).getStr().indexOf(op, fi);
                fw.setColnum(fi + ls.get(i).getColnum());
                fw.setLex(lex);
                this.reslist.add(fw); 
            }
        }
	return l;
    }
    
    public List<MarkedString> matchByRegexp(List<MarkedString> ls, 
    		String regexp, String lex){
    	List<MarkedString> l = new ArrayList<MarkedString>();
        Pattern p3 = Pattern.compile(regexp);
        for(int i = 0; i < ls.size(); i++){
            Matcher m2 = p3.matcher(ls.get(i).getStr());
            if (m2.matches()){
                ResString fw = new ResString();
                fw.setStrnum(ls.get(i).getStrnum());
                fw.setStr(ls.get(i).getStr());
                fw.setColnum(ls.get(i).getColnum());
                fw.setLex(lex);
                this.reslist.add(fw); 
            }else {
            	l.add(ls.get(i));
            }
            
        }
	return l;
    }
    
    public List<MarkedString> splitByIDent(List<MarkedString> ls, 
    		 String lex){
    	List<MarkedString> l = new ArrayList<MarkedString>();
        Pattern p3 = Pattern.compile(idRX);
        List<MarkedString> l1 = new ArrayList<MarkedString>();
        for(int i = 0; i < ls.size(); i++){
            String[] words = p3.split(ls.get(i).getStr());
            int fi = 0;
            for(String word : words){
            	MarkedString fw = new MarkedString();
            	fw.setStrnum(ls.get(i).getStrnum());
            	fw.setStr(word);
            	fi = ls.get(i).getStr().indexOf(word, fi);
            	fw.setColnum(fi + ls.get(i).getColnum());
            	l.add(fw); 
            }
            Matcher m2 = p3.matcher(ls.get(i).getStr());
            fi = 0;
            while (m2.find()){
                String op = m2.group();
                MarkedString fw = new MarkedString();
                fw.setStrnum(ls.get(i).getStrnum());
                fw.setStr(op);
            	fi = ls.get(i).getStr().indexOf(op, fi);
            	fw.setColnum(fi + ls.get(i).getColnum());
            	l1.add(fw);
            }
        }
        List<MarkedString> l2 = new ArrayList<MarkedString>();
        l2 =  this.matchByRegexp(l1, LexicalAnalisys.CONSTRX, "con");
        l1 =  this.matchByRegexp(l2, LexicalAnalisys.RESERVEDRX, "res");
        for(MarkedString it : l1){
        	ResString fw = new ResString();
        	fw.setStrnum(it.getStrnum());
        	fw.setStr(it.getStr());
        	fw.setColnum(it.getColnum());
            fw.setLex(lex);
            this.reslist.add(fw); 
        }
	return l;
    }

    /**
     * @return the reslist
     */
    public List<ResString> getReslist() {
        return this.reslist;

    }    
}